
#include "includes.h"
#include "exportToVTK.h"
#include "MRE.h"
#include "FileManager.h"
#include "Rebuilder.h"
#include <string>
#include <sstream>
#include "ErrorEstimator.h"

// LA EM FILE MANAGER FUNCTIONS TEM UM IF QUE EU NAO ESTOU GOSTANDO... ENCONTRAR UMA MANEIRA DE CORRIGIR O PROBLEMA.

// Criar rotina para definir o valor de newids na funcao Merge_msh da classe FileManager - é o valor do maior ID da malha que deve receber os elementos copiados, colocar na funcao iterador uma rotina para verificar isso, e depois na Merge_msh uma rotina para atualizar o valor de newids, newids a partir de entao deverá ser uma variavel da classe, nao mais da funcao.



// Tem uma rotina em Merge_msh que itera atraves de todas as faces para conseguir os pontos de contorno, pesquisar a funcao que retorna as arestas de contorno do FMDB para nao ter que usar este iterador, eu ja vi essa funcao...

// Ainda tem iteradores que percorrem toda a malha no programa, encontrar essas rotinas e eliminá-las - Em Identifysurfaces_2D tem um desses, verficar se é possível colocá-lo na funcao Iterador


// Avancar com o 3D por que nao dá pra esperar

// Fazer uma vista em todo o programa para procurar irregularidades



// Corrigir copias de malhas nas funcoes, colocar referencias & e tipo const

// Retirar os comandos system rm pois funcionam apenas no linux, substituir por ios::trunc





// Rotina que refine as geometrias curvas

// Fortalecer o removestgelements - todos os boundary nodes so podem estar ligados a dua boundaryedges cada um






int main(int argc, char **argv){
	ParUtil::Instance()->init(argc,argv);

	pMesh theMesh;

	theMesh = MS_newMesh(0);

	M_load(theMesh,argv[1]);


	theMesh->modifyState(3,2,1);
	theMesh->modifyState(3,1,1);
	theMesh->modifyState(3,0);

	theMesh->modifyState(2,1);
	theMesh->modifyState(2,3);
	theMesh->modifyState(2,0);

	theMesh->modifyState(1,3);
	theMesh->modifyState(1,2);
	theMesh->modifyState(1,0);

	theMesh->modifyState(0,2);
	theMesh->modifyState(0,1);
	theMesh->modifyState(0,3);


	// Aqui testando o merge das malhas

	int arestassolitarias = 0;

	EIter eit = M_edgeIter(theMesh);
	while (pEdge entity = EIter_next(eit))
	{
	if (E_numFaces(entity)<2){
		arestassolitarias++;
	}
	}
	EIter_delete(eit);




	// Aqui um simulador de estimador de erro
	ErrorEstimator *E;

	E = new ErrorEstimator(theMesh);
	//E->FacesList (theMesh);

	E->LeitorDeLista(theMesh);
	
	E->Calc_Factor();

	E->VertexList (theMesh);

	E->Calc_Cl (theMesh,0.1); // o float aqui é o fator de tamanho...

	E->SaveFileListCls ();

	E->SaveFileListFaces();








	FileManager *Reader;
	Reader = new FileManager();
	Reader->FileReader(argv[2]); // Esta funcao está lendo o arquivo que contem a lista de ids dos elementos a ser removidos e salvando em um set ListofElements (lista de ids), este set será usado pelas funcoes BoundaryElements3D e BoundaryElements2D

	//int I = Reader->ReturnIdent(); // retorna o identificador, se os elementos a ser removidos sao faces ou tetras.
	exportSolutionToVTK(theMesh,0,0,0,"vtks/theMesh_0.vtk");

	int I=0;
	if (M_numRegions(theMesh)!=0){ // verificando se a malha é 3D ou 2D...
		I=3; // malha 3D
	}
	else{
		I=2; // malha 2D
	}

	cout << "Num tetras: " << M_numRegions(theMesh) << endl;
	cout << "Num vertices: " << M_numVertices(theMesh) << endl;
	cout << "Num faces: " << M_numFaces(theMesh) << endl;

	theMesh->modifyState(3,2,1);
	theMesh->modifyState(3,1,1);
	theMesh->modifyState(3,0);

	theMesh->modifyState(2,1);
	theMesh->modifyState(2,3);
	theMesh->modifyState(2,0);

	theMesh->modifyState(1,3);
	theMesh->modifyState(1,2);
	theMesh->modifyState(1,0);

	theMesh->modifyState(0,2);
	theMesh->modifyState(0,1);
	theMesh->modifyState(0,3);

	//cout << "Num edges: " << M_numEdges(theMesh) << endl; // Parece que esta dando problema esta linha...


	int VerCL = 0;
	//double Cl = 0.2; // É o Cl que for escolhido para o refinamento



	istringstream ss( argv[3] );
	double Cl;
	ss >> Cl;   // Pegando o valor de Cl que é o valor do refinamento ou desrefinamento da malha, é usado pela funcao BoundaryElements

	cout << "o Cl inserido é: " << Cl << endl;

	Remover *p;
	
	p = new Remover(theMesh);

/*
	if (I==2){
	p->CriadordeLista(theMesh); // lembrar de tirar essa chamada de funcao depois (ela só serve pra me indicar uma lista de elementos vizinhos que formam uma regiao "buraco").
	}
	else{
	p->CriadordeLista3D(theMesh);
	}
*/

	p->ClReader("ListaCls"); // Esta funcao lê o arquivo com a lista de pontos com seus respectivos cls

	p->Iterador(Reader->ReturnListofElements(), I, theMesh); // PAULO DIZ QUE O GMSH JA DA OS ELEMENTOS DE FRONTEIRA, VERIFICAR ISSO.
	

	// Atribuindo CL = 0 a todos os nodes
	VIter vit = M_vertexIter(theMesh);
	while (pVertex Vertex = VIter_next(vit)){
		EN_attachDataDbl (Vertex, MD_lookupMeshDataId("CL"), 0);
	}
	VIter_delete(vit);


	//float GE;




	
	if (I==2){	

	

	p->BoundaryElements2D(Reader->ReturnListofElements(), Cl, VerCL,theMesh); // recebe o set de faces a remover set<pFace> BoundaryFaces e a partir dele preenche os boundaryedges e boundarynodes, inicialmente recebe todos os faces (nao apenas os de contorno), mas depois das funcoes de remoção só sobram os boundary mesmo, daí o nome do set.
	//}

	float GE = p->GreatestEdge; // Pegando o valor da maior aresta ANTES de rodar a funcao Boundaryelements2D novamente, quando ela rodar de novo, esse valor vai ser substituido, por isso tenho que guardá-lo agora.

	p->SaveBGMView1(Cl,GE); // Salvando o arquivo da View da malha de background.


	VerCL=1;

	//   AGORA TENHO QUE CHAMAR AS FUNCOES IDENTIFICADORAS.

	int PSCounter = 0;  // Contador de plane surfaces

	//PSCounter=p->identifysurfaces_2D(theMesh); // Esta funcao identifica os Plane Surfaces antes da remocao dos elementos, assim se quando a funcao RemoveStgElements remover mais algum, será necessario identificar os novos elementos de contorno também.

	p->removetetras(theMesh); // removendo os tetraedros indicados na lista


	p->removeinternalfaces(theMesh); // removendo as faces indicadas na lista
	
	theMesh->modifyState(1,2,0);
	theMesh->modifyState(1,2,1);
	theMesh->modifyState(2,1,0);
	theMesh->modifyState(2,1,1);

	p->RemoveStgElements_2D(theMesh,GE); // DAR UMA OLHADA AQUI E RETIRAR ROTINAS QUE NAO ESTEJAM MAIS SENDO USADAS

	theMesh->modifyState(1,2,0);
	theMesh->modifyState(1,2,1);
	theMesh->modifyState(2,1,0);
	theMesh->modifyState(2,1,1);

	cout << "Testando a remocao das arestas antes de Identify_and_Remove_Edges_2D" << M_numEdges(theMesh) << endl << endl;

	PSCounter=p->Identify_and_Remove_Edges_2D(theMesh);

	cout << "Testando a remocao das arestas depois de Identify_and_Remove_Edges_2D" << M_numEdges(theMesh) << endl << endl;	

	p->removeinternaledges(theMesh); // removendo as arestas das faces que foram removidas

	cout << "Testando a remocao das arestas depois de removeinternaledges" << M_numEdges(theMesh) << endl << endl;	



	theMesh->modifyState(0,1,0);
	theMesh->modifyState(0,1);

	p->removeinternalnodes(theMesh); // removendo os pontos que foram indicados na lista

	theMesh->modifyState(0,1,0);
	theMesh->modifyState(0,1,1);
	theMesh->modifyState(0,2,0);
	theMesh->modifyState(0,2,1);



	//p->removestgNodes(theMesh);  // FUNCAO NOVA... :D



	// Vou deixar as funcoes que removem elementos da fronteira desligadas por enquanto. 



	// Esta funcao remove elementos "estranhos" (dentes nos contornos, elementos que estejam causando uniao de lineloops, faces 		soltas no interior do buraco...)

	//p->RemoveStgElements_2D(theMesh,GE);

	cout << "Vai comecar SaveBGMView2" << endl;

	p->SaveBGMView2(GE); // Salvando o arquivo da View da malha de background.



	exportSolutionToVTK(theMesh,0,0,0,"vtks/theMesh_4.vtk");

	// Agora salvando os arquivos:



		FileManager *fm;
		fm = new FileManager(theMesh, p->ReturnBoundaryEdges(), p->ReturnBoundaryNodes(),PSCounter);
		//fm->SaveFile1_2D(); // Salva a malha, removidos os elementos, em formato NNF
		//fm->SaveFile2_2D();
		fm->SaveFileGeometry_2D(GE, theMesh);  // Neste momento o cl dos elementos é o comprimento da maior aresta
		//fm->SaveIGESGeometry_2D();
		fm->ResetFileManager();
		//}





	p->removeexternaledges(theMesh);

	p->removeexternalnodes(theMesh);

	cout << "Procurando o SF" << endl;

		theMesh->modifyState(3,2,1);
		theMesh->modifyState(3,1,1);
		theMesh->modifyState(3,0);

		theMesh->modifyState(2,1);
		theMesh->modifyState(2,3);
		theMesh->modifyState(2,0);
	
		theMesh->modifyState(1,3);
		theMesh->modifyState(1,2);
		theMesh->modifyState(1,0);
	
		theMesh->modifyState(0,2);
		theMesh->modifyState(0,1);
		theMesh->modifyState(0,3);










		// Agora a chamando as funcoes MakeMesh e RefineMesh para recriar a malha com a geometria recém salva em fm->SaveFileGeometry_2D();
		Rebuilder *Q;
		Q = new Rebuilder();
								//////////////////////////
		//Q->MakeMesh_2D("Geometria2D"); ////////////////// Mudar para a versao 1 ///////////////////
								/////////////////////////




			////////////////////////////////////////////////////////////////////////
		// Tenho que colocar aqui uma funcao que salve a malha em versao 1, acho que ja criei uma... (criei uma que salva um arquivo já lido, nao criei uma que leia um arquivo na versao 2...
			////////////////////////////////////////////////////////////////////////





		// A partir daqui, começa a geração da malha de adaptação

		pMesh theMesh2;

		theMesh2 = MS_newMesh(0);
		
		cout << "Lendo Geometria22D.msh" << endl;

		//M_load(theMesh2,"Geometria22D.msh");

		cout << "Lido o arquivo de malha gerado" << endl;

		cout << "Num edges: " << M_numEdges(theMesh2) << endl;


		theMesh2->modifyState(3,2,1);
		theMesh2->modifyState(3,1,1);
		theMesh2->modifyState(3,0);

		theMesh2->modifyState(2,1);
		theMesh2->modifyState(2,3);
		theMesh2->modifyState(2,0);

		theMesh2->modifyState(1,3);
		theMesh2->modifyState(1,2);
		theMesh2->modifyState(1,0);

		theMesh2->modifyState(0,2);
		theMesh2->modifyState(0,1);
		theMesh2->modifyState(0,3);

		



		if (Q->MkMesh == 1){ // Essa variavel é alterada pra 1 se alguma funcao MakeMesh for chamada. Se foi chamada alguma funcao Makemesh, (criada a segunda malha, entao essa deve ser lida)

// To pensando que nao precisa desse if aqui em cima...



		theMesh->modifyState(3,2,1);
		theMesh->modifyState(3,1,1);
		theMesh->modifyState(3,0);

		theMesh->modifyState(2,1);
		theMesh->modifyState(2,3);
		theMesh->modifyState(2,0);
	
		theMesh->modifyState(1,3);
		theMesh->modifyState(1,2);
		theMesh->modifyState(1,0);
	
		theMesh->modifyState(0,2);
		theMesh->modifyState(0,1);
		theMesh->modifyState(0,3);

		fm->SaveFileMshRenumber(theMesh, "theMesh.msh",0); // Este terceiro parametro é o ponto inicial de contagem dos ids
		fm->SaveFileMshRenumber2(theMesh2, "theMesh2.msh",M_numVertices(theMesh));




		//fm->Merge_msh_V2(theMesh,theMesh2);



		//fm->Merge_msh(theMesh,theMesh2);

		theMesh->modifyState(3,2,1);
		theMesh->modifyState(3,1,1);
		theMesh->modifyState(3,0);

		theMesh->modifyState(2,1);
		theMesh->modifyState(2,3);
		theMesh->modifyState(2,0);
	
		theMesh->modifyState(1,3);
		theMesh->modifyState(1,2);
		theMesh->modifyState(1,0);
	
		theMesh->modifyState(0,2);
		theMesh->modifyState(0,1);
		theMesh->modifyState(0,3);


	//	fm->SaveFileMshRenumber(theMesh3, "theMesh3.msh");

		exportSolutionToVTK(theMesh,0,0,0,"vtks/theMesh_3.vtk");
		exportSolutionToVTK(theMesh2,0,0,0,"vtks/theMesh_2.vtk");





	cout << "A MAIOR ARESTA É " << GE << endl;



	//fm->Merge_msh_V2(theMesh,theMesh2);

	} 




	}// Chave la da linha 153 if (I==2)...




	//		Começando o 3D


	if (I==3){

	cout << "comecou o 3D" << endl;

	p->BoundaryElements3D(Reader->ReturnListofElements(), theMesh); // recebe a lista de elementos e preenche o set Tetras com os tetras que serao removidos -- COMENTADO PARA NAO DAR SEGMENTATION FAULT



	VerCL=1;

	//   AGORA TENHO QUE CHAMAR AS FUNCOES IDENTIFICADORAS.

	int VLCounter = 0;  // Contador de Volumes

	VLCounter=p->identifyvolumes_3D(theMesh); // Esta funcao identifica os Volumes antes da remocao dos elementos, assim se quando a funcao RemoveStgElements remover mais algum, será necessario identificar os novos elementos de contorno também.


	// AGORA AS FUNCOES DE REMOCAO DE ELEMENTOS

	p->removetetras(theMesh); // removendo os tetraedros indicados na lista

	p->removeinternalfaces(theMesh); // removendo as faces indicadas na lista
	
	theMesh->modifyState(1,2,0);
	theMesh->modifyState(1,2);

	p->removeinternaledges(theMesh); // removendo as arestas internas

	theMesh->modifyState(0,1,0);
	theMesh->modifyState(0,1);

	p->removeinternalnodes(theMesh); // removendo os pontos internos

	theMesh->modifyState(0,1,0);
	theMesh->modifyState(0,1,1);
	theMesh->modifyState(0,2,0);
	theMesh->modifyState(0,2,1);

	cout << "concluiu as rotinas de remocao" << endl;


	// Criar funcao SaveFileGeometry3D que pega as faces de contorno e cria lineloops e plane surface com cada uma e depois as une todas em um volume.


	cout << "VLCounter: " << VLCounter << endl;

	FileManager *fm;
	fm = new FileManager(theMesh,p->ReturnBoundaryFaces(), p->ReturnBoundaryEdges(), p->ReturnBoundaryNodes(),VLCounter);

	fm->SaveFileGeometry_3D(Cl);

	exportSolutionToVTK(theMesh,0,0,0,"vtks/theMesh_1.vtk");

	}	

		ParUtil::Instance()->Finalize();
		return 0;
	}
//}

